// MyAddressListBox.cpp : implementation file
//

#include "stdafx.h"
#include "8085.h"
#include "MyAddressListBox.h"
#include "NumericBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMyAddressListBox

CMyAddressListBox::CMyAddressListBox() : CListBox(),CCommonObject()
{
	Init();
}

CMyAddressListBox::~CMyAddressListBox()
{
    // bug - delete [] gives a core dump i don't know why
    if(m_nPrev!=NULL)    delete [] m_nPrev;
    m_nPrev = NULL;
	if(m_aDisplay!=NULL) delete [] m_aDisplay;
    m_aDisplay = NULL;
}


BEGIN_MESSAGE_MAP(CMyAddressListBox, CListBox)
	//{{AFX_MSG_MAP(CMyAddressListBox)
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_VSCROLL()
	ON_WM_ERASEBKGND()
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()
	ON_WM_CTLCOLOR_REFLECT()
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(ID_MODIFY_DATA, OnModifyData)
	ON_COMMAND(ID_TOGGLE_BREAKPOINT, OnToggleBreakpoint)
	ON_COMMAND(ID_ENABLE_DISABLE_BKPT, OnEnableDisableBkpt)
	ON_COMMAND(ID_SHOW_SOURCE_LINE, OnShowSourceLine)
	ON_WM_KEYUP()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyAddressListBox message handlers

void CMyAddressListBox::CalculateListBoxProperty(RECT &r)
{
    GetClientRect(&m_Rect);
    m_nHeight = m_Rect.bottom - m_Rect.top;
    m_nItemHeight = r.bottom - r.top;
    m_nItemsDisplayed = m_nItems = m_nHeight/m_nItemHeight;
	int i;
	if(m_aDisplay==NULL) 
	{
        m_aDisplay = new OneDisplayElement[m_nItems+4];
		for( i=0; i<m_nItems+4; i++)
			m_aDisplay[i].szMnemonic[0]='\0';
	}

    for(i=0; i<m_nItems; i++)
        m_aDisplay[i].bModified = m_aDisplay[i].data = 0;
    // this is done to make the scroll bar active
    for(i=0; i<m_nItems*3; i++)
        InsertString(-1,"10/07/75");
    SetScrollPos(SB_VERT,GetCount()/4);
    SetSel(1);

    // call this virtual function to perform more initializations
    // that is specific to the individual display boxes
    SetIndividualProperty();    
}

void CMyAddressListBox::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
    SetFocus();
    BOOL bOutside;
    m_nSelectedIndex = ItemFromPoint(CPoint(point.x,point.y),bOutside);
    InvalidateRect(NULL);
    m_bRedrawBkgnd = FALSE;
}

void CMyAddressListBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
    if(GetDocument()->IgnoreInputs()) 
        return;
	if(nChar==VK_CONTROL)
		m_bCtrlDown =  TRUE;
    m_nLastKey=nChar;         // value of the last key pressed
	OnVirtualKeyDown(nChar,nRepCnt,nFlags);
	//CListBox::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CMyAddressListBox::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	if(nChar==VK_CONTROL)
		m_bCtrlDown=FALSE;
	
	CListBox::OnKeyUp(nChar, nRepCnt, nFlags);
}

void CMyAddressListBox::OnVirtualLButtonDblClk(UINT nFlags, CPoint point)
{
    if(GetDocument()->IgnoreInputs()) 
        return;
    EnterValidData();
}

void CMyAddressListBox::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
    if(GetDocument()->IgnoreInputs()) 
        return;
	OnVirtualLButtonDblClk(nFlags,point);
	//CListBox::OnLButtonDblClk(nFlags, point);
}

void CMyAddressListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
    if(GetDocument()->IgnoreInputs()) 
        return;
	OnVirtualVScroll(nSBCode,nPos,pScrollBar);
	//CListBox::OnVScroll(nSBCode, nPos, pScrollBar);
}

BOOL CMyAddressListBox::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	return FALSE;
	//return CListBox::OnEraseBkgnd(pDC);
}

void CMyAddressListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS) 
{
	// TODO: Add your code to draw the specified item
	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
	COLORREF defBackground = GetSysColor(COLOR_WINDOW); // RGB in item data
    COLORREF textColor=GetSysColor(COLOR_MENUTEXT); 
    m_cFrame.SetRect(lpDIS->rcItem.left+m_nMarginWidth,lpDIS->rcItem.top,
    lpDIS->rcItem.right,lpDIS->rcItem.bottom);
    m_cTextFrame.SetRect(m_cFrame.left,m_cFrame.top+2,m_cFrame.right,m_cFrame.bottom-1);
    CBrush br(defBackground);
    BOOL bOutside;
    int nIndex = ItemFromPoint(CPoint(lpDIS->rcItem.left,lpDIS->rcItem.top),bOutside);

    pDC->SetBkMode(OPAQUE);
    pDC->FillRect(&lpDIS->rcItem,&br);

    // item has been selected - hilite m_cFrame
    if(m_nSelectedIndex==nIndex)
    {
		if(GetFocus()==this)
		{
			CBrush b(GetSysColor(COLOR_HIGHLIGHT));
			pDC->FillRect(&m_cFrame,&b);
			m_cSelectedFrame = m_cFrame;
			textColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
		}
        m_nSelectedIndex = nIndex;
		COLORREF crHilite = RGB(255-GetRValue(defBackground),
						255-GetGValue(defBackground), 255-GetBValue(defBackground));
		CBrush br(crHilite);
        pDC->SetBkMode(TRANSPARENT);
		pDC->FrameRect(&m_cFrame, &br);
    }
    if(m_aDisplay[nIndex].bModified) pDC->SetTextColor(RGB(200,0,0));
    else pDC->SetTextColor(textColor);
    pDC->SetBkColor(defBackground);
    pDC->ExtTextOut(lpDIS->rcItem.left+m_nMarginWidth+2,lpDIS->rcItem.top,ETO_CLIPPED,
        m_cTextFrame,m_aDisplay[nIndex].szMnemonic,NULL);
}

void CMyAddressListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS) 
{
	// TODO: Add your code to determine the size of specified item
	lpMIS->itemWidth = 20;
	lpMIS->itemHeight = 20;
}

int CMyAddressListBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct) 
{
	// TODO: Add your code to determine the sorting order of the specified items
	// return -1 = item 1 sorts before item 2
	// return 0 = item 1 and item 2 sort the same
	// return 1 = item 1 sorts after item 2
	
	return 0;
}

void CMyAddressListBox::AllocatePrevArray()
{
    ASSERT(Get8085Object()->GetSegmentSize()>m_nItems);
    if(m_nPrev!=NULL) delete [] m_nPrev;
    m_nPrev = new int[Get8085Object()->GetSegmentSize()];
}

void CMyAddressListBox::Display()
{
    m_bRedrawBkgnd = FALSE;
	InvalidateRect(NULL);
}

void CMyAddressListBox::Init()
{
	m_aDisplay = NULL;
	m_nPrev =NULL;
    m_nPropertySet = 0;
    m_nItemHeight = 0;  
    m_nItems=0;       
    m_nHeight=0;      
    m_bRedrawBkgnd=TRUE;	
    m_nMarginWidth=0; 
    m_nSelectedIndex=0;
    m_nFirstAddress=0;
    m_nLastAddress=0;
	m_cSelectedFrame.SetRectEmpty();
    m_nItemsDisplayed = 0;
    m_cMenu.LoadMenu(IDR_LISTBOX_POPUP);
    AllocatePrevArray();
    SetMaxSize(0);
    m_bCtrlDown = m_bShiftDown = FALSE;
}

int CMyAddressListBox::RefreshStrings(int addr,BOOL bCheckModified)
{
    return 0;
}

BOOL CMyAddressListBox::IsNumber(char * str, int & number)
{
    if(str==NULL || *str=='\0') return FALSE;
    char *endptr;

    if(*str=='0')
    {
        ++str;
        if(*str=='x') 
        {
            ++str;
            number = strtol(str,&endptr,16);
        }
        else number = strtol(str,&endptr,8);
    }
    else number = strtol(str,&endptr,10);
    if(*endptr!='\0') return FALSE;
    return TRUE;
}

void CMyAddressListBox::OnSetFocus(CWnd* pOldWnd) 
{
	//CListBox::OnSetFocus(pOldWnd);
	InvalidateRect(&m_cSelectedFrame);
}

void CMyAddressListBox::OnKillFocus(CWnd* pNewWnd) 
{
	//CListBox::OnKillFocus(pNewWnd);
	InvalidateRect(&m_cSelectedFrame);
}

void CMyAddressListBox::PreSubclassWindow() 
{
	// TODO: Add your specialized code here and/or call the base class
	RECT r;
	GetItemRect(0,&r);
	CalculateListBoxProperty(r);
    m_nPropertySet=1;
    RefreshStrings();
    CWnd *p = GetParent();
    
	CListBox::PreSubclassWindow();
}

HBRUSH CMyAddressListBox::CtlColor(CDC* pDC, UINT nCtlColor) 
{
	// TODO: Change any attributes of the DC here
	LOGFONT lf;
    CFont m_Font;
	GetFont()->GetLogFont(&lf);
    //lf.lfHeight = 18;
    //lf.lfWidth = 8;
    lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
    strcpy(lf.lfFaceName,"Courier");
	m_Font.CreateFontIndirect(&lf);
    pDC->SelectObject(&m_Font);
	// TODO: Return a non-NULL brush if the parent's handler should not be called
	return (HBRUSH)GetStockObject(NULL_BRUSH);
}

void CMyAddressListBox::SetIndividualProperty()
{

}


void CMyAddressListBox::EnterData()
{

}

void CMyAddressListBox::Refresh()               
{
    RefreshStrings(m_nFirstAddress);
    InvalidateRect(NULL);
}


void CMyAddressListBox::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	// TODO: Add your message handler code here
    UpdateWindow();
    CMenu* pPopup = m_cMenu.GetSubMenu(0);
    BOOL state = GetDocument()->IsAnimating();
    pPopup->EnableMenuItem(ID_MODIFY_DATA,state);

    EnableDisableMenuItems();
    pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
      point.x, point.y,this); // use main window for cmds
}

void CMyAddressListBox::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
    SetFocus();
    BOOL bOutside;
    m_nSelectedIndex = ItemFromPoint(CPoint(point.x,point.y),bOutside);
    InvalidateRect(NULL);
    m_bRedrawBkgnd = FALSE;
	//CListBox::OnRButtonDown(nFlags, point);
}

void CMyAddressListBox::OnModifyData() 
{
	// TODO: Add your command handler code here
    EnterValidData();	
}

void CMyAddressListBox::OnToggleBreakpoint() 
{
	// TODO: Add your command handler code here
    if(ToggleBreakPoint()) Refresh();	
}

int CMyAddressListBox::ToggleBreakPoint()
{
    return 0;
}


void CMyAddressListBox::EnableDisableMenuItems()
{

}

void CMyAddressListBox::EnableDisableBkPt()
{

}

void CMyAddressListBox::OnEnableDisableBkpt() 
{
	// TODO: Add your command handler code here
    EnableDisableBkPt();	
}

void CMyAddressListBox::OnVirtualKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    switch(nChar)
    {
    case VK_HOME    :   
        if(m_nFirstAddress==0 && m_nSelectedIndex==0) return;
        m_nSelectedIndex = m_nFirstAddress =0;
        m_nLastAddress = RefreshStrings(0,FALSE);
        break;

    case VK_END     :   
        if(!MoveToEnd()) return;
        break;

    case VK_PRIOR   :  
        if(!MoveOnePageUp()) return;
        break;
    
    case VK_NEXT    :  
        if(!MoveOnePageDown()) return;
        break;

    case VK_UP      :
        if(!MoveOneAddressUp()) return;
        break;

    case VK_DOWN    :
        if(!MoveOneAddressDown()) return;
        break;

    case 0x47       :   // key code for 'G', VK_G did not work, I don't know why
        if(!GotoAddress()) return;
        break;

    case VK_ADD     :   
        IncrementData();
        RefreshStrings();
        break;

    case VK_SUBTRACT:   
        DecrementData();
        RefreshStrings();
        break;

    case VK_CONTROL:
        m_bCtrlDown=TRUE;
        break;
    
    case VK_SHIFT:
        m_bShiftDown=TRUE;
        break;

    default     :
        return;
    }
    InvalidateRect(m_Rect);
}

int CMyAddressListBox::MoveOneAddressUp()
{
    if(m_nSelectedIndex==0 && m_nFirstAddress==0) return 0;
    if(m_nSelectedIndex==0)
    {
        --m_nFirstAddress;
        m_nLastAddress = RefreshStrings(m_nFirstAddress,FALSE);
    }
    else --m_nSelectedIndex;
    return 1;
}

int CMyAddressListBox::MoveOneAddressDown()
{
    if(m_nSelectedIndex==m_nItems-1 && m_nLastAddress==GetMaxSize()) return 0;
    if(m_nSelectedIndex==m_nItems-1)
    {
        ++m_nFirstAddress;
        m_nLastAddress = RefreshStrings(m_nFirstAddress,FALSE);
    }
    else ++m_nSelectedIndex;
    return 1;
}

int CMyAddressListBox::MoveToEnd()
{
    if(m_nLastAddress==GetMaxSize() && m_nSelectedIndex==m_nItems-1) return 0;

    if(m_nLastAddress==GetMaxSize())
    {
        m_nSelectedIndex = m_nItems-1;
        return 1;
    }
    m_nFirstAddress = GetMaxSize()-m_nItems+1;
    m_nLastAddress=GetMaxSize();
    RefreshStrings(m_nFirstAddress,FALSE);
    m_nSelectedIndex = m_nItems-1;
    return 1;
}

int CMyAddressListBox::MoveOnePageUp()
{
    if(m_nSelectedIndex==0 && m_nFirstAddress==0) return 0;
    if(m_nFirstAddress<m_nItems)
    {
        m_nFirstAddress=0;
        m_nSelectedIndex = 0;
    }
    else  m_nFirstAddress -= m_nItems;
    m_nLastAddress = RefreshStrings(m_nFirstAddress,FALSE);
    return 1;
}

int CMyAddressListBox::MoveOnePageDown()
{
    if(m_nLastAddress==GetMaxSize() && m_nSelectedIndex==m_nItems-1) return 0;
    if(m_nLastAddress+m_nItems>GetMaxSize())
    {
        m_nFirstAddress = GetMaxSize()-m_nItems;
        m_nSelectedIndex = m_nItems-1;
    } 
    else m_nFirstAddress += m_nItems;
    m_nLastAddress = RefreshStrings(m_nFirstAddress,FALSE);
    return 1;
}

int CMyAddressListBox::GotoAddress()
{
    CNumericBox g;
    int nAddress;

    g.SetCaption("Enter a Valid Address");
    if(!g.DisplayNumericBox(nAddress,0,GetMaxSize())) return 0;
    if(nAddress>=m_nFirstAddress && nAddress<=m_nLastAddress)
    {
        if(m_nSelectedIndex==AddressAtIndex(nAddress)) return 0;
        m_nSelectedIndex= m_nFirstAddress - m_nLastAddress;
    }
    else
    {
        if(nAddress+m_nItems>=GetMaxSize())
            m_nFirstAddress = GetMaxSize()-m_nItems;
        else m_nFirstAddress=nAddress;
        m_nLastAddress = RefreshStrings(m_nFirstAddress,FALSE);
        m_nSelectedIndex = 0;
    }
    return 1;
}

void CMyAddressListBox::OnVirtualVScroll(UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
{
	if (nSBCode == SB_LINEDOWN)
    {
        // don't overshoot
        if(m_nFirstAddress+m_nItems>=GetMemSize()) return;
        m_nFirstAddress++;
    }
	else if (nSBCode == SB_LINEUP)
    {
        if(m_nFirstAddress<=0) return;
        m_nFirstAddress--;
    }
    RefreshStrings(m_nFirstAddress,FALSE);
    InvalidateRect(NULL);
}

void CMyAddressListBox::DecrementData()
{

}

void CMyAddressListBox::IncrementData()
{

}

void CMyAddressListBox::OnShowSourceLine() 
{
	// TODO: Add your command handler code here
	
}

int CMyAddressListBox::IndexAtAddress(word nAddress)
{
    m_nItems = m_nHeight/m_nItemHeight;
    for(int i=0; i<m_nItems ; i++)
    {
        if(nAddress==m_aDisplay[i].address)
            return i;
    }
    return -1;
}


BOOL CMyAddressListBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	// TODO: Add your message handler code here and/or call default
	
	return 1; //CListBox::OnMouseWheel(nFlags, zDelta, pt);
}

void CMyAddressListBox::EnterValidData() 
{
	if((m_nSelectedIndex<0) || (m_nSelectedIndex >= m_nItemsDisplayed) )
		return;
	EnterData();
}
